'use strict';

/**
 * Spring animation configuration.
 *
 * @param mass - The weight of the spring. Reducing this value makes the animation faster. Defaults to 1.
 * @param damping - How quickly a spring slows down. Higher damping means the spring will come to rest faster. Defaults to 10.
 * @param duration - Length of the animation (in milliseconds). Defaults to 2000.
 * @param dampingRatio - How damped the spring is. Value 1 means the spring is critically damped, and value \>1 means the spring is overdamped. Defaults to 0.5.
 * @param stiffness - How bouncy the spring is. Defaults to 100.
 * @param velocity - Initial velocity applied to the spring equation. Defaults to 0.
 * @param overshootClamping - Whether a spring can bounce over the `toValue`. Defaults to false.
 * @param restDisplacementThreshold - The displacement below which the spring will snap to toValue without further oscillations. Defaults to 0.01.
 * @param restSpeedThreshold - The speed in pixels per second from which the spring will snap to toValue without further oscillations. Defaults to 2.
 * @param reduceMotion - Determines how the animation responds to the device's reduced motion accessibility setting. Default to `ReduceMotion.System` - {@link ReduceMotion}.
 * @see https://docs.swmansion.com/react-native-reanimated/docs/animations/withSpring/#config-
 */

// This type contains all the properties from SpringConfig, which are changed to be required, except for optional 'reduceMotion'

export function checkIfConfigIsValid(config) {
  'worklet';

  let errorMessage = '';
  ['stiffness', 'damping', 'dampingRatio', 'restDisplacementThreshold', 'restSpeedThreshold', 'mass'].forEach(prop => {
    const value = config[prop];
    if (value <= 0) {
      errorMessage += `, ${prop} must be grater than zero but got ${value}`;
    }
  });
  if (config.duration < 0) {
    errorMessage += `, duration can't be negative, got ${config.duration}`;
  }
  if (errorMessage !== '') {
    console.warn('[Reanimated] Invalid spring config' + errorMessage);
  }
  return errorMessage === '';
}
function bisectRoot(_ref) {
  'worklet';

  let {
    min,
    max,
    func,
    maxIterations = 20
  } = _ref;
  const ACCURACY = 0.00005;
  let idx = maxIterations;
  let current = (max + min) / 2;
  while (Math.abs(func(current)) > ACCURACY && idx > 0) {
    idx -= 1;
    if (func(current) < 0) {
      min = current;
    } else {
      max = current;
    }
    current = (min + max) / 2;
  }
  return current;
}
export function initialCalculations() {
  'worklet';

  let mass = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
  let config = arguments.length > 1 ? arguments[1] : undefined;
  if (config.skipAnimation) {
    return {
      zeta: 0,
      omega0: 0,
      omega1: 0
    };
  }
  if (config.useDuration) {
    const {
      stiffness: k,
      dampingRatio: zeta
    } = config;

    /** omega0 and omega1 denote angular frequency and natural angular frequency, see this link for formulas:
     *  https://courses.lumenlearning.com/suny-osuniversityphysics/chapter/15-5-damped-oscillations/
     */
    const omega0 = Math.sqrt(k / mass);
    const omega1 = omega0 * Math.sqrt(1 - zeta ** 2);
    return {
      zeta,
      omega0,
      omega1
    };
  } else {
    const {
      damping: c,
      mass: m,
      stiffness: k
    } = config;
    const zeta = c / (2 * Math.sqrt(k * m)); // damping ratio
    const omega0 = Math.sqrt(k / m); // undamped angular frequency of the oscillator (rad/ms)
    const omega1 = omega0 * Math.sqrt(1 - zeta ** 2); // exponential decay

    return {
      zeta,
      omega0,
      omega1
    };
  }
}
export function calculateNewMassToMatchDuration(x0, config, v0) {
  'worklet';

  if (config.skipAnimation) {
    return 0;
  }

  /** Use this formula: https://phys.libretexts.org/Bookshelves/University_Physics/Book%3A_University_Physics_(OpenStax)/Book%3A_University_Physics_I_-_Mechanics_Sound_Oscillations_and_Waves_(OpenStax)/15%3A_Oscillations/15.06%3A_Damped_Oscillations
       * to find the asymptote and estimate the damping that gives us the expected duration 
             ⎛ ⎛ c⎞           ⎞           
            ⎜-⎜──⎟ ⋅ duration⎟           
            ⎝ ⎝2m⎠           ⎠           
       A ⋅ e                   = threshold
  
      Amplitude calculated using "Conservation of energy"
                       _________________
                      ╱      2         2
                     ╱ m ⋅ v0  + k ⋅ x0 
      amplitude =   ╱  ─────────────────
                  ╲╱           k        
       And replace mass with damping ratio which is provided: m = (c^2)/(4 * k * zeta^2)   
      */
  const {
    stiffness: k,
    dampingRatio: zeta,
    restSpeedThreshold: threshold,
    duration
  } = config;
  const durationForMass = mass => {
    'worklet';

    const amplitude = (mass * v0 * v0 + k * x0 * x0) / (Math.exp(1 - 0.5 * zeta) * k);
    const c = zeta * 2 * Math.sqrt(k * mass);
    return 1000 * (-2 * mass / c) * Math.log(threshold * 0.01 / amplitude) - duration;
  };

  // Bisection turns out to be much faster than Newton's method in our case
  return bisectRoot({
    min: 0,
    max: 100,
    func: durationForMass
  });
}
export function criticallyDampedSpringCalculations(animation, precalculatedValues) {
  'worklet';

  const {
    toValue
  } = animation;
  const {
    v0,
    x0,
    omega0,
    t
  } = precalculatedValues;
  const criticallyDampedEnvelope = Math.exp(-omega0 * t);
  const criticallyDampedPosition = toValue - criticallyDampedEnvelope * (x0 + (v0 + omega0 * x0) * t);
  const criticallyDampedVelocity = criticallyDampedEnvelope * (v0 * (t * omega0 - 1) + t * x0 * omega0 * omega0);
  return {
    position: criticallyDampedPosition,
    velocity: criticallyDampedVelocity
  };
}
export function underDampedSpringCalculations(animation, precalculatedValues) {
  'worklet';

  const {
    toValue,
    current,
    velocity
  } = animation;
  const {
    zeta,
    t,
    omega0,
    omega1
  } = precalculatedValues;
  const v0 = -velocity;
  const x0 = toValue - current;
  const sin1 = Math.sin(omega1 * t);
  const cos1 = Math.cos(omega1 * t);

  // under damped
  const underDampedEnvelope = Math.exp(-zeta * omega0 * t);
  const underDampedFrag1 = underDampedEnvelope * (sin1 * ((v0 + zeta * omega0 * x0) / omega1) + x0 * cos1);
  const underDampedPosition = toValue - underDampedFrag1;
  // This looks crazy -- it's actually just the derivative of the oscillation function
  const underDampedVelocity = zeta * omega0 * underDampedFrag1 - underDampedEnvelope * (cos1 * (v0 + zeta * omega0 * x0) - omega1 * x0 * sin1);
  return {
    position: underDampedPosition,
    velocity: underDampedVelocity
  };
}
export function isAnimationTerminatingCalculation(animation, config) {
  'worklet';

  const {
    toValue,
    velocity,
    startValue,
    current
  } = animation;
  const isOvershooting = config.overshootClamping ? current > toValue && startValue < toValue || current < toValue && startValue > toValue : false;
  const isVelocity = Math.abs(velocity) < config.restSpeedThreshold;
  const isDisplacement = Math.abs(toValue - current) < config.restDisplacementThreshold;
  return {
    isOvershooting,
    isVelocity,
    isDisplacement
  };
}
//# sourceMappingURL=springUtils.js.map